﻿//
// Created by LiuYou on 2021/4/24.
//

#include "Widget.hpp"

// ============================================================

#ifdef ORIGIN

Original::Widget::Widget() = default;

#endif

// ============================================================

#ifdef CPP98_PIMPL

#include <string>
#include <vector>
#include "CustomClass.hpp"

// TODO 注意: WidgetImpl实现要写在 Cpp98Pimpl::Widget::Widget() : ptr(new WidgetImpl()) {}
//  构造函数之上, 不然ptr(new WidgetImpl()) 会报错: 类型不完整！
struct Cpp98Pimpl::Widget::WidgetImpl {
    std::string name;
    std::vector<double> data;
    CustomClass customClass;
};

Cpp98Pimpl::Widget::Widget() : ptr(new WidgetImpl()) {}

Cpp98Pimpl::Widget::~Widget() {
    delete ptr;
}

#endif


// ============================================================

#ifdef CPP_MODERN_PIMPL
// TODO 3
// TODO 注意: 所以要加上这些需要的头文件的！
#include <string>
#include <vector>
#include <ostream>
#include "CustomClass.hpp"

// TODO 2
// TODO 注意: 当写上了这个具体类的定义还是不行的！因为还需要含入这个具体类中定义对象的类型所在的头文件！
struct CppModernPimpl::Widget::WidgetImpl {
    std::string name;
    std::vector<double> data;
    CustomClass customClass;

    WidgetImpl();

    WidgetImpl(const std::string& name, const CustomClass& customClass);

    friend std::ostream& operator<<(std::ostream& os, const WidgetImpl& widget) {
        os << "name: " << widget.name << " customClass: " << widget.customClass;
        return os;
    }
};

CppModernPimpl::Widget::WidgetImpl::WidgetImpl(const std::string& name, const CustomClass& customClass) : name(name),
                                                                                                          customClass(
                                                                                                                  customClass) {}

CppModernPimpl::Widget::WidgetImpl::WidgetImpl() = default;

// TODO 1
// TODO 注意: 报错 In template: invalid application of 'sizeof' to an incomplete type 'CppModernPimpl::Widget::WidgetImpl'
//  在模板中：'sizeof'的无效应用到不完整的类型'CppModernPimpl :: Widget :: WidgetImpl'
//  这个错误和宏CPP98PIMPL中出现的问题是一个问题就是类型不完整！需要将具体的实现类放到构造函数前面(使用了实现类的函数们前面)！
CppModernPimpl::Widget::Widget() : ptr(std::make_unique<WidgetImpl>()) {

}

const std::string& CppModernPimpl::Widget::getName() const {
    return ptr->name;
}

const std::vector<double>& CppModernPimpl::Widget::getData() const {
    return ptr->data;
}

const CustomClass& CppModernPimpl::Widget::getCustomClass() const {
    return ptr->customClass;
}

std::ostream& CppModernPimpl::operator<<(std::ostream& os, const CppModernPimpl::Widget& widget) {
    os << "Widget: " << *widget.ptr;
    return os;
}

//std::ostream& CppModernPimpl::operator<<(std::ostream& os, const CppModernPimpl::Widget& widget) {
//    os << "Widget: " << *widget.ptr;
//    return os;
//}

CppModernPimpl::Widget::Widget(const std::string& name, const CustomClass& customClass) : ptr(
        std::make_unique<WidgetImpl>()) {
    ptr->name = name;
    ptr->customClass = customClass;
}

// TODO 注意: 我们希望的是可以拷贝std::unique_ptr指向的内容(即, 进行深拷贝！)
CppModernPimpl::Widget::Widget(const Widget& rhs) : ptr(std::make_unique<WidgetImpl>(*rhs.ptr)) {}

// TODO 注意: 深拷贝
CppModernPimpl::Widget& CppModernPimpl::Widget::operator=(const CppModernPimpl::Widget& rhs) {
    *ptr = *rhs.ptr;
    return *this;
}

//const std::unique_ptr<CppModernPimpl::Widget::WidgetImpl>& CppModernPimpl::Widget::getPtr() const {
//    return ptr;
//}
//
//std::unique_ptr<CppModernPimpl::Widget::WidgetImpl>& CppModernPimpl::Widget::getPtr() {
//    return ptr;
//}

CppModernPimpl::Widget::~Widget() = default;

#endif
